﻿/*!
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

using System;
using System.Collections.Generic;

namespace Pittypat
{
    /// <summary>
    /// 表示一个字符串值。
    /// </summary>
    public struct @string : IPrimitive, IEnumerable<char>
    {
        /// <summary>
        /// 表示空字符串。
        /// </summary>
        public static readonly @string Empty = new @string("");

        private string value;

        /// <summary>
        /// 初始化 @string 结构的新实例。
        /// </summary>
        /// <param name="value">字符串的值，如果为空引用，也看作为一个空字符串。</param>
        public @string(string value)
        {
            this.value = value ?? "";
        }

        // 当前字符串值，确保总是返回非空引用的字符串。
        string Value
        {
            get
            {
                return this.value ?? "";
            }
        }

        /// <summary>
        /// 获取一个值，该值指示此字符串是否是空字符串。
        /// </summary>
        public bool IsEmpty
        {
            get
            {
                return this.value == null || this.value.Length == 0;
            }
        }

        /// <summary>
        /// 获取此字符串的长度。
        /// </summary>
        public int Length
        {
            get
            {
                return this.value == null ? 0 : this.value.Length;
            }
        }

        /// <summary>
        /// 获取指定位置处的字符。
        /// </summary>
        /// <param name="index">从 0 开始的索引位置。</param>
        /// <returns>目标位置上的字符。</returns>
        public char this[int index]
        {
            get
            {
                return this.Value[index];
            }
        }

        /// <summary>
        /// 将当前值转换为 string 类型的值。
        /// </summary>
        /// <param name="value">要转换的值。</param>
        /// <returns>转换后的值。</returns>
        public static implicit operator string(@string value)
        {
            return value.value ?? "";
        }

        /// <summary>
        /// 将指定的值转换为 @string 类型的值。
        /// </summary>
        /// <param name="value">要转换的值。</param>
        /// <returns>转换后的值。</returns>
        public static implicit operator @string(string value)
        {
            return new @string(value);
        }

        /// <summary>
        /// 比较两个值是否相等，不区分大小写。
        /// </summary>
        /// <param name="x">第一个值。</param>
        /// <param name="y">第二个值。</param>
        /// <returns>如果两个值相等，则返回 true，否则返回 false。</returns>
        public static bool operator ==(@string x, @string y)
        {
            return string.Equals(x.value ?? "", y.value ?? "", StringComparison.InvariantCultureIgnoreCase);
        }

        /// <summary>
        /// 比较两个值是否不相等，不区分大小写。
        /// </summary>
        /// <param name="x">第一个值。</param>
        /// <param name="y">第二个值。</param>
        /// <returns>如果两个值不相等，则返回 true，否则返回 false。</returns>
        public static bool operator !=(@string x, @string y)
        {
            return !string.Equals(x.value ?? "", y.value ?? "", StringComparison.InvariantCultureIgnoreCase);
        }

        /// <summary>
        /// 判断两个值是否相等，不区分大小写。
        /// </summary>
        /// <param name="obj">要比较的值。</param>
        /// <returns>如果两个值相等，则返回 true，否则返回 false。</returns>
        public override bool Equals(object obj)
        {
            if (obj is @string)
            {
                return string.Equals(((@string)obj).value ?? "", this.value ?? "", StringComparison.InvariantCultureIgnoreCase);
            }

            if (obj is @string?)
            {
                var s = obj as @string?;
                if (s.HasValue)
                {
                    return string.Equals(s.Value.value ?? "", this.value ?? "", StringComparison.InvariantCultureIgnoreCase);
                }
                else
                {
                    return false;
                }
            }

            if (obj is string)
            {
                return string.Equals(((string)obj) ?? "", this.value ?? "", StringComparison.InvariantCultureIgnoreCase);
            }

            return string.Equals((obj == null ? "" : obj.ToString()), this.value ?? "", StringComparison.InvariantCultureIgnoreCase);
        }

        /// <summary>
        /// 返回此值的哈希代码。
        /// </summary>
        /// <returns>此值的哈希代码。</returns>
        public override int GetHashCode()
        {
            return this.value == null ? 0 : this.value.GetHashCode();
        }

        /// <summary>
        /// 返回此值的字符串表示形式。
        /// </summary>
        /// <returns>此值的字符串表示形式。</returns>
        public override string ToString()
        {
            return this.Value;
        }

        #region IPrimitive Members

        object IPrimitive.Value
        {
            get
            {
                return this.Value;
            }
        }

        /// <summary>
        /// 将当前对象作为 JSON 字符串写入指定的文本流。
        /// </summary>
        /// <param name="writer">目标文本流。</param>
        /// <exception cref="ArgumentNullException">writer 是 null。</exception>
        public void Write(System.IO.TextWriter writer)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }

            writer.Write("\"{0}\"", Json.Escape(this.Value));
        }

        #endregion

        #region IConvertible Members

        TypeCode IConvertible.GetTypeCode()
        {
            return TypeCode.Object;
        }

        bool IConvertible.ToBoolean(IFormatProvider provider)
        {
            string v = this.Value.ToLower();
            return v == "true" || v == "t" || v == "1" || v == "yes" || v == "y" || v == "是";
        }

        byte IConvertible.ToByte(IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToByte(provider);
        }

        char IConvertible.ToChar(IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToChar(provider);
        }

        DateTime IConvertible.ToDateTime(IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToDateTime(provider);
        }

        decimal IConvertible.ToDecimal(IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToDecimal(provider);
        }

        double IConvertible.ToDouble(IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToDouble(provider);
        }

        short IConvertible.ToInt16(IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToInt16(provider);
        }

        int IConvertible.ToInt32(IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToInt32(provider);
        }

        long IConvertible.ToInt64(IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToInt64(provider);
        }

        sbyte IConvertible.ToSByte(IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToSByte(provider);
        }

        float IConvertible.ToSingle(IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToSingle(provider);
        }

        string IConvertible.ToString(IFormatProvider provider)
        {
            return this.Value;
        }

        object IConvertible.ToType(Type conversionType, IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToType(conversionType, provider);
        }

        ushort IConvertible.ToUInt16(IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToUInt16(provider);
        }

        uint IConvertible.ToUInt32(IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToUInt32(provider);
        }

        ulong IConvertible.ToUInt64(IFormatProvider provider)
        {
            return ((IConvertible)this.Value).ToUInt64(provider);
        }

        #endregion

        #region IComparable Members

        int IComparable.CompareTo(object other)
        {
            if (other is @string)
            {
                return this.Value.CompareTo(((@string)other).Value);
            }

            return 1;
        }

        #endregion

        #region IFormattable Members

        /// <summary>
        /// 使用指定的格式格式化当前实例的值。
        /// </summary>
        /// <param name="format">指定要使用的格式的 String。</param>
        /// <param name="formatProvider">用于格式化该值的 IFormatProvider。null 表示从操作系统的当前区域设置中获取数字格式信息。</param>
        /// <returns>一个 String，包含具有指定格式的当前实例的值。</returns>
        public string ToString(string format, IFormatProvider formatProvider)
        {
            if (format == null)
            {
                return this.Value;
            }

            if (format == "")
            {
                return "";
            }

            return String.Format(format, this.Value);
        }

        /// <summary>
        /// 使用指定的格式格式化当前实例的值。
        /// </summary>
        /// <param name="format">指定要使用的格式的 String。</param>
        /// <returns>一个 String，包含具有指定格式的当前实例的值。</returns>
        public string ToString(string format)
        {
            return this.ToString(format, null);
        }

        #endregion

        #region IEnumerable<char> Members

        /// <summary>
        /// 返回用于对此字符串进行枚举的枚举器。
        /// </summary>
        /// <returns>用于对此字符串进行枚举的枚举器。</returns>
        public IEnumerator<char> GetEnumerator()
        {
            return this.Value.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.Value.GetEnumerator();
        }

        #endregion
    }
}
